﻿/*
【简介】
本类用于研究 async 和 await 关键字 (C# 5.0引入)

【心得】
1. await 使用后，会进行异步调用，然后返回主线程继续执行其他任务，如UI界面响应
2. 当异步调用完成后，主线程会回到 await 处，继续执行后面的代码


【日志】
2022/05/11 添加此类
*/

using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;

namespace VerficationsWPF.Verfications
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class AsyncTestWindow : Window
    {
        CancellationTokenSource cts = new CancellationTokenSource();
        TaskFactory taskFactory = new TaskFactory();

        public Func<object> AsyncTask = default!;

        public AsyncTestWindow()
        {
            InitializeComponent();
        }

        private async void btnSimpleTest_Click(object sender, RoutedEventArgs e)
        {
            txtOutput.Clear();
            print("Main: Start");
            await SunAsync();
            print("Main: Done");
            // await Task.Run<object>(AsyncTask);
        }


        private async void btnCanncellableTest_Click(object sender, RoutedEventArgs e)
        {
            txtOutput.Clear();
            btnCancel.IsEnabled = true;
            btnCancel.Content = "Need Cancel 2 times";
            print($"Starting a new task.");
            cts = new CancellationTokenSource();
            taskFactory = new TaskFactory(cts.Token);

            // 启动一个新线程，随机1100 正负 500 ms 后停止后续的线程
            _ = Task.Run(() =>
              {
                  Thread.Sleep(600 + Random.Shared.Next(1000));
                  cts.Cancel();
              });

            print($"Starting new a task...");
            await taskFactory.StartNew(
                  () =>
                  {
                      try
                      {
                          print($"A new task started.");
                          for (int i = 0, len = 10; i < len; i++)
                          {
                              print($"countdown: {len - i}...");
                              Thread.Sleep(100);
                              cts.Token.ThrowIfCancellationRequested();
                          }
                          print($"A new task completed.");
                      }
                      catch (Exception ex)
                      {
                          print("Error. ex = " + ex.Message);
                      }
                  });
            print("t1 done.");
            btnCancel.Content = "Need Cancel 1 times";

            if (!cts.IsCancellationRequested)
            {
                Task<int> t2 = taskFactory.StartNew(
                () =>
                {
                    try
                    {
                        print($"A new task started.");
                        for (int i = 0, len = 20; i < len; i++)
                        {
                            print($"countdown: {len - i}...{cts.Token.IsCancellationRequested}");
                            Thread.Sleep(200);
                            cts.Token.ThrowIfCancellationRequested();
                        }
                        print($"A new task completed.");
                    }
                    catch (Exception ex)
                    {
                        print("Error. ex = " + ex.Message);
                    }
                    return 0;
                });

                await t2;
                print("t2 done, and after await and exit.");
            }
            btnCancel.Content = "Cancal";
            btnCancel.IsEnabled = false;
        }

        private void btnCancel_Click(object sender, RoutedEventArgs e)
        {
            cts.Cancel();
            print("cts.Cancle()");
        }


        //public async Task<int> ExampleMethodAsync()
        //{
        // (1) To do some code here synchronously...
        // (2) To do something asynchronously....
        //     await SunAsync();
        // (3) To do some code here after awiat code...
        //}

        public async Task SunAsync()
        {
            print($"Starting a new task.");
            var t = Task.Run(() =>
            {
                print($"A new task started.");
                for (int i = 0; i < 10; i++)
                {
                    Thread.Sleep(400);
                    print($"I am playing game...");
                }
            });

            print($"After Task, before await.");

            await t;

            print($"After await, before SunAsync() exit.");
        }

        public void print(string msg)
        {
            string fmt_msg = $"{DateTime.Now: HH:mm:ss.fff} {Thread.CurrentThread.ManagedThreadId}: {msg}";
            Debug.WriteLine(fmt_msg);
            txtOutput.Dispatcher.Invoke(() =>
            {
                txtOutput.Text += fmt_msg + "\n";
                txtOutput.SelectionStart = txtOutput.Text.Length;
                txtOutput.Focus();
            });
        }

        /// <summary>
        /// 在弹出新窗体后，执行异步任务，即使窗体退出，事务也会继续进行。所以可以在Window_Closing中进行关闭，并处理后续业务。
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnNewWindow_Click(object sender, RoutedEventArgs e)
        {
            new AsyncTestWindow().ShowDialog();
        }

        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            cts.Cancel();
            print("Window_Closing: cts.Cancle()");
        }

        private void btnDelay_Click(object sender, RoutedEventArgs e)
        {
            print("Delay 5 seconds.");
            Thread.Sleep(5000);
            print("Delay is over.");

        }
    }
}
